package com.study.spring.proxy.core;

import com.study.spring.proxy.util.EmptyUtil;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.*;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.ClassUtils;

import java.util.EmptyStackException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class SaosHttpClientRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private static final PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
    private static final MetadataReaderFactory METADATA_READER_FACTORY = new SimpleMetadataReaderFactory();


    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        String className = importingClassMetadata.getClassName();
        Map<String, Object> attrs = importingClassMetadata.getAnnotationAttributes(EnableSaosHttpClients.class.getName());
        System.out.println(attrs);
        String basePackages = (String)attrs.get("basePackages");
        Set<Class> classes = doScan(basePackages);
        boolean primy = true;
        if(EmptyUtil.isNotEmpty(classes)){
            for (Class aClass : classes) {
                String name = aClass.getName();
                String simpleName = aClass.getSimpleName();
                BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(SaosHttpFactoryBean.class);
                definition.addConstructorArgValue(aClass);
                definition.setAutowireMode(2);
                String alias = simpleName + "SaosFeignClient";
                AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
                if(primy){
                    beanDefinition.setPrimary(true);
                    primy = false;
                }else{
                    beanDefinition.setPrimary(false);
                }
                BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, simpleName, new String[]{alias});
                BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);

            }
        }
    }

    private Set<Class> doScan(String basePackage) {
        Set<Class> allSaosHttpClient = new HashSet<Class>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(environment.resolveRequiredPlaceholders(basePackage)) + '/' + "**/*.class";

            Resource[] resources = pathMatchingResourcePatternResolver.getResources(packageSearchPath);
            for (Resource resource : resources) {
                MetadataReader metadataReader = METADATA_READER_FACTORY.getMetadataReader(resource);
                ClassMetadata classMetadata = metadataReader.getClassMetadata();
                boolean isInterface = classMetadata.isInterface();
                if(isInterface){
                    Class<?> annotationClass = Class.forName(classMetadata.getClassName());
                    boolean hasSaosHttpClient = annotationClass.isAnnotationPresent(SaosHttpClient.class);
                    if(hasSaosHttpClient){
                        allSaosHttpClient.add(annotationClass);
                    }
                }

            }
        } catch (Exception e) {
            throw new BeanDefinitionStoreException("exception failure during classpath scanning", e);
        }
        return allSaosHttpClient;
    }
}
